////////////////////////////////////////////////////////////////////////////////
//Copyright (c) 2010 Michal Szczepanski - (http://vane.pl)
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
package pl.vane.net.services
{
	import flash.errors.IllegalOperationError;
	import flash.events.Event;
	
	/**
	 * URLServiceBase Class is responsible for managing loaded content.
	 * 
	 * It's FIFO(First In First Out) stack based with configurable 
	 * maximum amount connections and ability to remove loaders
	 * 
	 * @see pl.vane.net.services.URLLoaderBase
	 * @see pl.vane.net.services.IURLResponder
	 * 
	 * @langversion ActionScript 3.0
	 * @playerversion Flash 9.0
	 * @tiptext
	 */ 
	public class URLServiceBase implements IURLServiceBase
	{
		/**
		 * Sets number of connections available
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */ 
		public static var MAX_CONNECTIONS:int = 3;
		
		/**
		 * @private
		 */ 
		private var _loaders:Array; 
		
		/**
		 * @private
		 */ 
		private var _stack:Array;
		
		/**
		 * Constructor.
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */ 
		public function URLServiceBase()
		{
			preinitialize();
		}
		
		/**
		 * Stops loading specified url.
		 * 
		 * @return Boolean Disposes all loaders (<code>true</code>) or (<code>false</code>).
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */ 
		public function stopLoader(url:String):Boolean {
			var i:int;
			while(i<MAX_CONNECTIONS) {
				if(URLLoaderBase(_loaders[i]).url == url) {
					URLLoaderBase(_loaders[i]).dispose();
					return true;
				}  
				++i;
			}
			return false;
		}
		
		/**
		 * Empty the loading stack.
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */
		public function emptyStack():void {
			_stack = [];
		}
		
		/**
		 * Stops loading from all services.
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */
		public function dispose():void {
			var i:int;
			while(i<MAX_CONNECTIONS) {
				URLLoaderBase(_loaders[i]).dispose();
				++i;
			}
			emptyStack();
		}
		
		/**
		 * Loads request(s) and pass results to the responder(s).
		 * 
		 * @param requests <code>Array</code> of <code>URLRequest</code>
		 * @param responder One or <code>Array</code> of IURLResponder class
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 9.0
		 * @tiptext
		 */ 
		public function loadFiles(request:Array, responder:*):void {
			var i:int;
			// if there is more then one request and responder
			if(responder is Array) {
				// Throws error if number of responders doesn't match number of requests
				if(!request.length == responder.length) throw new IllegalOperationError('responder and request length does not match');
				// Loads the request if the _stack is not full
				while(i<MAX_CONNECTIONS) {
					if(!URLLoaderBase(_loaders[i]).busy) {
						if(request.length > 0)
							// TODO: make sure responder is pl.vane.net.services.IURLResponder
							URLLoaderBase(_loaders[i]).loadRequest(request.pop(), responder.pop());
						else
							break;
					}
					++i;
				}
				if(request.length > 0) {
					// if there are requests left and stack is full it push requests to the stack
					while(request.length > 0) {
						_stack.push({'request':request.pop(), 'responder':responder.pop()});
					}
				}
			} else {
				if(!(responder is IURLResponder)) throw new IllegalOperationError('wrong responder');
				while(i<MAX_CONNECTIONS) {
					if(!URLLoaderBase(_loaders[i]).busy) {
						if(request.length > 0)
							URLLoaderBase(_loaders[i]).loadRequest(request.pop(), responder);
						else
							break;
					}
					++i;
				}
				if(request.length > 0) {
					while(request.length > 0) {
						_stack.push({'request':request.pop(), 'responder':responder});
					}
				}
			}
			
		}
		
		/**
		 * @private
		 */ 
		private function loaderReadyHandler(event:Event):void {
			if(_stack.length > 0) {
				var i:int;
				while(i<MAX_CONNECTIONS) {
					if(!URLLoaderBase(_loaders[i]).busy) {
						var o:Object = _stack.pop();
						URLLoaderBase(_loaders[i]).loadRequest(o.request, o.responder);
					}
					++i;
				}
			}
		}
		
		/**
		 * @private
		 */ 
		private function preinitialize():void {
			_loaders = [];
			_stack = [];
			var i:int;
			while(i<MAX_CONNECTIONS) {
				_loaders[i] = new URLLoaderBase();
				URLLoaderBase(_loaders[i]).addEventListener("event.ready", loaderReadyHandler);
				++i;
			}
		}
	}
}
